<?
class Actor {
	
	protected $data = array();
	protected $partesCorpoEquip = array();
	protected $equip_objs;
	protected $inv_objs;
	protected $conditionStates;
	protected $arma;
	
	function __construct ($nome, $raca, $genero) {
		$this->data['id']			= rand(1,999999);
		$this->data['nome']			= $nome;
		if ($genero=='m') {
			$this->data['nome_art'] = 'o'; $this->data['nome_art_ind'] = 'um';
		} else {
			$this->data['nome_art'] = 'a'; $this->data['nome_art_ind'] = 'uma';
		}
		$this->data['area_nome']	= null;

		$this->data['raca_nome']	= $raca->getValue('nome');
		$this->data['portrait_img']	= $raca->getValue('portrait_img');
		
		$this->data['combateId']		= null;
		$this->data['ultimo_acesso']	= floor(time());
		
		$this->data['level'] 		= 1;
		$this->data['xp'] 			= 1;
		$this->data['ouro'] 		= 4000;
		$this->data['peso'] 		= 0;
		
		// 1=fine, 2=diminutive, 3=minusculo, 4=pequeno, 5=m�dio, 6=grande, 7=enorme, 8=gigantesco, 9=colossal
		$this->data['size']			= $raca->getValue('size');
		$this->data['hp']			= $raca->getValue('hp') / 2;
		$this->data['hp_max']		= $raca->getValue('hp');
		$this->data['initiative']	= $raca->getValue('initiative');
		$this->data['speed']		= $raca->getValue('speed');
		
		$this->data['nonLethalDamage']	= 0;
		
		$this->data['naturalArmor']		= $raca->getValue('naturalArmor');
		$this->data['touchArmor']		= $raca->getValue('touchArmor');
		
		$this->data['baseAttack']		= $raca->getValue('baseAttack');
		$this->data['grapleAttack']		= $raca->getValue('grapleAttack');
		
		$this->data['saveFortitude']	= $raca->getValue('saveFortitude');
		$this->data['saveReflex']		= $raca->getValue('saveReflex');
		$this->data['saveWill']			= $raca->getValue('saveWill');
		
		$this->data['str']			= $raca->getValue('str');
		$this->data['dex']			= $raca->getValue('dex');
		$this->data['con']			= $raca->getValue('con');
		$this->data['int']			= $raca->getValue('int');
		$this->data['wis']			= $raca->getValue('wis');
		$this->data['car']			= $raca->getValue('car');
		$this->data['vision']		= $raca->getValue('vision');
		
		$this->arma = $raca->getArma();
		
		$this->parteCorpoEquip['arma']		= null;
		$this->parteCorpoEquip['escudo']	= null;
		$this->parteCorpoEquip['cabeca']	= null;
		$this->parteCorpoEquip['camisola']	= null;
		$this->parteCorpoEquip['calcas']	= null;
		$this->parteCorpoEquip['pes']		= null;
		
		$this->parteCorpoEquip['pescoco']	= null;
		$this->parteCorpoEquip['ombros']	= null;
		$this->parteCorpoEquip['bracos']	= null;
		$this->parteCorpoEquip['maos']		= null;
		$this->parteCorpoEquip['tronco']	= null;
		$this->parteCorpoEquip['cintura']	= null;
		$this->parteCorpoEquip['pernas']	= null;
		$this->parteCorpoEquip['joelhos']	= null;
		
		
		$this->equip_objs 	= new ListaDeElementos;
		$this->inv_objs 	= new ListaDeElementos;
		$this->feiticos 	= new ListaDeElementos;
		$this->conditionStates 	= new ListaDeElementos;
		$this->conditionStates->adiciona('flat-footed');
		
		$this->actualizar();
	}
	
	public function getCombateId() {
		if ($this->getValue('combateId') == null) return false;
		else return $this->getValue('combateId');
	}
	
	private function getBodyArmor($parteDoCorpo) {
		if (is_subclass_of($this->parteCorpoEquip[$parteDoCorpo], 'ObjEscudo'))
			return $this->parteCorpoEquip[$parteDoCorpo]->getArmadura()->getValue('armorBonus');
		else return 0;
	}
	
	private function getBodyMaxDexBonus($parteDoCorpo) {
		if (is_subclass_of($this->parteCorpoEquip[$parteDoCorpo], 'ObjEscudo'))
			return $this->parteCorpoEquip[$parteDoCorpo]->getArmadura()->getValue('max_dex_bonus');
		else return 0;
	}
	
	private function getArmorBonus() {
		$armor_bonus += $this->getBodyArmor('cabeca');
		$armor_bonus += $this->getBodyArmor('camisola');
		$armor_bonus += $this->getBodyArmor('calcas');
		$armor_bonus += $this->getBodyArmor('pes');
		
		$armor_bonus += $this->getBodyArmor('pescoco');
		$armor_bonus += $this->getBodyArmor('ombros');
		$armor_bonus += $this->getBodyArmor('bracos');
		$armor_bonus += $this->getBodyArmor('maos');
		$armor_bonus += $this->getBodyArmor('tronco');
		$armor_bonus += $this->getBodyArmor('cintura');
		$armor_bonus += $this->getBodyArmor('pernas');
		$armor_bonus += $this->getBodyArmor('joelhos');
		
		return $armor_bonus;
	}
	
	private function getArmorMaxDexBonus() {
		$temp = $this->getBodyMaxDexBonus('cabeca');
		if ($this->getBodyMaxDexBonus('camisola')	< $temp) $temp = $this->getBodyMaxDexBonus('camisola');
		if ($this->getBodyMaxDexBonus('calcas')		< $temp) $temp = $this->getBodyMaxDexBonus('calcas');
		if ($this->getBodyMaxDexBonus('pes')		< $temp) $temp = $this->getBodyMaxDexBonus('pes');
		
		if ($this->getBodyMaxDexBonus('pescoco')	< $temp) $temp = $this->getBodyMaxDexBonus('pescoco');
		if ($this->getBodyMaxDexBonus('ombros')		< $temp) $temp = $this->getBodyMaxDexBonus('ombros');
		if ($this->getBodyMaxDexBonus('bracos')		< $temp) $temp = $this->getBodyMaxDexBonus('bracos');
		if ($this->getBodyMaxDexBonus('maos')		< $temp) $temp = $this->getBodyMaxDexBonus('maos');
		if ($this->getBodyMaxDexBonus('tronco')		< $temp) $temp = $this->getBodyMaxDexBonus('tronco');
		if ($this->getBodyMaxDexBonus('cintura')	< $temp) $temp = $this->getBodyMaxDexBonus('cintura');
		if ($this->getBodyMaxDexBonus('pernas')		< $temp) $temp = $this->getBodyMaxDexBonus('pernas');
		if ($this->getBodyMaxDexBonus('joelhos')	< $temp) $temp = $this->getBodyMaxDexBonus('joelhos');
		
		return $temp;
	}
	
	public function ingerir(&$target, $objecto) {
		// ATTACK ROLL
		$dado = new Dado(20);
		$attack_roll = $dado->lancar(1, 0);
		
		if ($attack_roll == 1) return false;
		return $objecto->aplicarEfeitos($target);
	}
		
	public function atacar(&$defensor, $combate, $manager, $html) {
		// GET ATTACKER MODIFIERS
		$att_size_mod = floor((6 - $this->getValue('size')) * 1.2);
		$att_str_mod = $this->getMod($this->getValue('str'));
		$att_dex_mod = $this->getMod($this->getValue('dex'));
		$att_con_mod = $this->getMod($this->getValue('con'));
		$att_int_mod = $this->getMod($this->getValue('int'));
		$att_wis_mod = $this->getMod($this->getValue('wis'));
		$att_car_mod = $this->getMod($this->getValue('car'));

		// GET DEFENDER MODIFIERS
		$def_size_mod = floor((6 - $defensor->getValue('size')) * 1.2);
		$def_str_mod = $defensor->getMod($defensor->getValue('str'));
		$def_dex_mod = $defensor->getMod($defensor->getValue('dex'));
		$def_con_mod = $defensor->getMod($defensor->getValue('con'));
		$def_int_mod = $defensor->getMod($defensor->getValue('int'));
		$def_wis_mod = $defensor->getMod($defensor->getValue('wis'));
		$def_car_mod = $defensor->getMod($defensor->getValue('car'));

		// ATTACK ROLL
		$dado = new Dado(20);
		$attack_roll = $dado->lancar(1, 0);

		// ARMOR CLASS
		$armor_bonus	= $defensor->getArmorBonus();
		$shield_bonus	= $defensor->getBodyArmor('escudo');
		if ($defensor->getArmorMaxDexBonus() && ($defensor->getArmorMaxDexBonus() < $def_dex_mod))
			$def_dex_mod = $defensor->getArmorMaxDexBonus();
		
		$armor_class = round(10 + $defensor->getValue('naturalArmor') + $armor_bonus + $shield_bonus + $def_dex_mod + $def_size_mod);
		
		//echo "defensor: armor_bonus=$armor_bonus, $shield_bonus, $def_dex_mod, $def_size_mod, ". $defensor->getValue('naturalArmor');
		
		if (is_subclass_of($this->getArma(), 'ObjArmaMelee')) $action = 'attack_melee';
		else $action = 'attack_ranged';
	
		//echo "<br />arma � ObjMelee: ". is_subclass_of($this->getArma(), 'ObjArmaMelee');
		if ($action == 'attack_ranged' && !$ranged_attack_allowed) $action = 'failed';

		if ($action!='failed') {
			if ($attack_roll > 1) {
				if ($action == 'attack_melee') {
					$armor_class += round($armor_on_melee_mod);
					$attack_roll += $melee_attack_mod;
					$attack_bonus = $this->getValue('baseAttack') + $att_str_mod + $att_size_mod;
				}
				if ($action == 'attack_ranged') {
					$armor_class += round($armor_on_ranged_mod);
					$attack_roll += $ranged_attack_mod;
					$attack_bonus = $this->getValue('baseAttack') + $att_dex_mod + $att_size_mod;
				}
			} else $attack_bonus = 0;
			
			// GET THE RESULT!
			$attack_roll += $attack_bonus;
			$resultado = $attack_roll - $armor_class;
				
			if ($resultado >= 0) {
				
				// DAMAGE ROLL
				$damage_roll = $this->getArma()->damage();
				if ($action == 'attack_melee') $dano_final = $damage_roll + $att_str_mod;
				if ($action == 'attack_ranged') $dano_final = $damage_roll + $att_dex_mod;
				/*
				echo '<br />action:'. $action;
				echo '<br />dano_final:'. $dano_final;
				echo ' = damage_roll:'. $damage_roll;
				echo ' + str_mod:'. $att_str_mod;
				*/
				// CRITICAL HIT
				$critical = $this->getArma()->getValue('critical');
				if ($damage_roll >= 20 - $critical[1]) $dano_final *= $critical[0];
				
				// DAMAGE IS AT LEAST 1
				if ($dano_final <= 0) $dano_final = 1;
				
			
				// ACTUALIZAR HP DO DEFENSOR
				if ($this->getArma()->getValue('nonLethalDamage')) {
					if ($defensor->getValue("nonLethalDamage") + $dano_final <= $defensor->getValue("hp")) {
						$defensor->setValue("nonLethalDamage", $defensor->getValue("nonLethalDamage") + $dano_final);
					} else {
						$defensor->setValue("nonLethalDamage", $defensor->getValue("hp"));
					}
					$html_result .= $html->mixArray($defensor->toArray(), 'actor_sofreu_dano_nao_letal');
				} else {
					if ($defensor->getValue("hp") - $dano_final >= -10) {
						$defensor->setValue("hp", $defensor->getValue("hp") - $dano_final);
					} else {
						$defensor->setValue("hp", -11);
					}
					$html_result .= $html->mixArray($defensor->toArray(), 'actor_sofreu_dano');
				}
			} else {
				$html_result .= $html->mixArray($this->toArray(), 'actor_falhou_accao_ataque');
			}
		} else {
			$html_result .= $html->mixArray($defensor->toArray(), 'actor_falhou_accao_ataque');
		}
		
		//echo "atacante=". $this->getValue('nome') . ", attack_roll=". $attack_roll. ", dano_final=" . $dano_final . ", defensor=". $defensor->getValue('nome') .", armor_class=". $armor_class;
		
		//var_dump($attack_roll); var_dump($armor_class); var_dump($dano_final);
	
		$html->set('com_result', $html_result);
	}
	
	public function getMod($value) {
		return $value & 1 ? $value - 11 : $value - 10;
	}

	public function updateModifiers($html) {
		$this->data['str_mod']		= $this->getMod($this->data['str']);
		$this->data['dex_mod']		= $this->getMod($this->data['dex']);
		$this->data['con_mod']		= $this->getMod($this->data['con']);
		$this->data['int_mod']		= $this->getMod($this->data['int']);
		$this->data['wis_mod']		= $this->getMod($this->data['wis']);
		$this->data['car_mod']		= $this->getMod($this->data['car']);
	}
	
	public function getConditionStates() {
		return $this->conditionStates;
	}
	
	public function getArma() {
		if ($this->parteCorpoEquip['arma'] != null) return $this->parteCorpoEquip['arma'];
		else return $this->arma;
	}
	
	public function actualizar() {
	
		for ($i=0; $i < $this->feiticos->numElementos(); $i++) {
			if ((floor(time()) - $this->feiticos->devolve($i)->getValue('time')) >=
				$this->feiticos->devolve($i)->getDuration[1])
				$this->feiticos->devolve($i)->desactivar($this);
		}
		
		$this->data['hp_stat_height']	= floor(($this->data['hp'] + 10) / ($this->data['hp_max'] + 10) * 110);
		$this->data['hp_stat_color']	= $this->getHpStatColor($this->data['hp_stat_height'], $this->data['hp']);
		$this->data['energy_stat_height']	= 110 - (floor(($this->data['nonLethalDamage']) / (1 + ($this->data['hp'] + 10)) * 100));
		$this->data['energy_perc']			= $this->data['energy_stat_height'] - 10;
		$this->data['energy_stat_color']	= $this->getEnergyStatColor($this->data['energy_perc']);
		
		//echo "<p>".$this->data['hp_perc'] ."</p>";
		$this->updateModifiers($html);
		
		$size_mod = floor((6 - $this->getValue('size')) * 1.2);
		
		//echo "arma_dano=".$this->getArma()->max_damage() . " size_mod=".$size_mod.", str_mod=".$this->getMod($this->data['str']) .", dex_mod=".$this->getMod($this->data['dex']);
		
		$this->data['dano_max']	= $this->getArma()->max_damage() + $size_mod;
		if (is_subclass_of($this->getArma(), 'ObjArmaMelee'))
			$this->data['dano_max'] += $this->getMod($this->data['str']);	
		else $this->data['dano_max'] += $this->getMod($this->data['dex']);
		
		//echo "dano_max=".$this->data['dano_max'];
		
		$armor_bonus = $this->getArmorBonus();
		$shield_bonus = $this->getBodyArmor('escudo');
		
		//echo 'AC = 10 + ' . $this->getValue('naturalArmor') .' (natural) + '. $armor_bonus .' (armor bonus) + '. $shield_bonus .' (shield bonus) + '. $this->getMod($this->data['dex']) . ' (dex_mod) + '. $size_mod . ' (size_mod)';
		$this->data['armor_class'] = round(10 + $this->getValue('naturalArmor') + $armor_bonus + $shield_bonus + $this->getMod($this->data['dex']) + $size_mod);
		
		$tempo = floor(time() - $this->getValue('ultimo_acesso'));
		$this->setValue('ultimo_acesso', floor(time()));

		if ($this->getValue('hp') + floor($tempo / 20) <= $this->getValue('hp_max'))
			$this->setValue('hp', $this->getValue('hp') + floor($tempo / 20));
		else $this->setValue('hp', $this->getValue('hp_max'));

		if ($this->getValue('nonLethalDamage') - floor($tempo / 5) >= 0)
			$this->setValue('nonLethalDamage', $this->getValue('nonLethalDamage') - floor($tempo / 5));
		else $this->setValue('nonLethalDamage', 0);
	}
	
	public function setArea($area) {
		$this->data['area_nome'] = $area->getValue('nome');
	}
	
	public function setValue($atrib, $valor) {
		$this->data[$atrib] = $valor;
	}
	
	public function existeFeitico($obj) {
		return $this->feiticos->existe($obj);
	}
	public function adicionaFeitico($obj) {
		return $this->feiticos->adiciona($obj);
	}
	public function removeFeitico($obj) {
		return $this->feiticos->remove($obj);
	}
	
	private function existeObjInv($obj) {
		return $this->inv_objs->existe($obj);
	}
	private function adicionaObjInv($obj) {
		return $this->inv_objs->adiciona($obj);
	}
	public function removeObjInv($obj) {
		return $this->inv_objs->remove($obj);
	}
	
	private function existeObjEquip($obj) {
		return $this->equip_objs->existe($obj);
	}
	private function adicionaObjEquip($obj) {
		return $this->equip_objs->adiciona($obj);
	}
	private function removeObjEquip($obj) {
		return $this->equip_objs->remove($obj);
	}
	
	public function getValue($key) {
		return $this->data[$key];
	}
	
	public function toArray() {
		$this->actualizar();
		return $this->data;
	}
	
	private function aplicarEfeitos($lista, $accao) {
		for ($i=0; $i<$lista->numElementos(); $i++) {
			if ($lista->devolve($i)->getValue('accao') == $accao)
				$this->data[$lista->devolve($i)->getValue('atributo')] += $lista->devolve($i)->getValue('valor');
		}
	}
	
	public function partesDoCorpoLivres($obj) {
		$i = 0;
		while ($i < $obj->getPartes()->numElementos()) {
			if ($this->parteCorpoEquip[$obj->getPartes()->devolve($i)] != null)
				$this->desequipar($this->parteCorpoEquip[$obj->getPartes()->devolve($i)]);
			$this->parteCorpoEquip[$obj->getPartes()->devolve($i)] = null;
			$i++;
		}
		return true;
	}
	
	private function equiparPartesDoCorpo($obj) {
		$i = 0;
		while ($i < $obj->getPartes()->numElementos()) {
			$this->parteCorpoEquip[$obj->getPartes()->devolve($i)] = $obj;
			$i++;
		}
		return true;
	}
	
	
	public function equipar($obj) {
		if (is_subclass_of($obj, 'ObjEquipamento')) {
			if ($this->partesDoCorpoLivres($obj)) {
				if ($this->removeObjInv($obj)) {
					if ($this->equiparPartesDoCorpo($obj)) {
						if ($this->adicionaObjEquip($obj)) {
							//$this->aplicarEfeitos($obj->getEfeitos(), 'equipar');
							return true;
						} else return false;
					} else return false;
				} else return false;
			} else return false;
		} else return false;
	}
	
	public function desequipar($obj) {
		if (is_subclass_of($obj, 'ObjEquipamento')) {
			if ($this->removeObjEquip($obj)) {
				//$this->aplicarEfeitos($obj->getEfeitos(), 'desequipar');
				if ($this->adicionaObjInv($obj)) {
					return true;
				} else return false;
			} else return false;
		} else return false;
	}
		
	public function apanhar($obj) {
		if ($this->adicionaObjInv($obj)) {
			$this->data['peso'] += $obj->getValue('peso');
			//$this->aplicarEfeitos($obj->getEfeitos(), 'apanhar');
			return true;
		} else return false;
	}
	
	public function largar($obj) {
		if ($this->existeObjEquip($obj)) $this->desequipar($obj);
		if ($this->removeObjInv($obj)) {
			$this->data['peso'] -= $obj->getValue('peso');
			//$this->aplicarEfeitos($obj->getEfeitos(), 'largar');
			return true;
		} else return false;
	}
	
	public function examinadoHtml($html, $agente_nivel) {
		$template = 'actor_examinado_small';
		if ($agente_nivel > 5) $template = 'actor_examinado_medium';
		if ($agente_nivel > 15) $template = 'actor_examinado_completo';
		$this->data['t_nome_art'] = ucfirst($this->getValue('nome_art'));
		return $html->mixArray($this->toArray(), $template);
	}
	
	public function toResumeHtml($html) {
		return $html->mixArray($this->toArray(), 'li_area_actor');
	}
	
	public function objsEquipListHtmlLink($siteHtml) {
		for ($x=0; $x<$this->equip_objs->numElementos(); $x++) {
			$tobj = $this->equip_objs->devolve($x);
			$thtml .= $tobj->toHtmlImgLink($siteHtml);
		}
		return $thtml;
	}
	
	public function objsInvListHtmlLink($siteHtml) {
		for ($x=0; $x<$this->inv_objs->numElementos(); $x++) {
			$tobj = $this->inv_objs->devolve($x);
			$thtml .= $tobj->toHtmlImgLink($siteHtml);
		}
		return $thtml;
	}
	
	public function getStatsHtml($siteHtml) {
		$statsHtml = new newString($this->data, $siteHtml->get('pers_stats_list'));
		return $statsHtml->mix();
	}
	
	private function getHpStatColor($value, $hp) {
		$color = 'red';
		if ($hp > 0) $color = 'yellow';
		if ($value > 43) $color = 'green';
		return $color;
	}
	
	private function getEnergyStatColor($energy_perc) {
		$color = 'green';
		if ($energy_perc < 50) $color = 'yellow';
		if ($energy_perc < 20) $color = 'red';
		return $color;
	}
}
?>